const add = (a, b) => a + b //var add =function add(a,b){return a+b}

// 词法分析器
const tokenizer = (code) => {
    const tokens = [] // 存储语法单元
    let curret = 0
    while (curret < code.length) {
        const char = code[curret]
        // ()语法单元
        if (char === '(' || char === ')') {
            tokens.push({
                type: 'parens',
                value: char
            })
            curret++
            continue
        }

        // _, $ 字母 语法单元
        if (/[a-zA-Z\$\_]/.test(char)) {
            let value = ''
            value += char
            curret++

            while (/[a-zA-Z0-9\$\_]/.test(code[curret]) && curret < code.length) {
                value += code[curret]
                curret++
            }

            tokens.push({
                type: 'identifier',
                value,
            })

            continue
        }

        // 空白字符
        if (/\s/.test(char)) {
            let value = ''
            value += char
            curret++

            while (/\s/.test(code[curret]) && curret < code.length) {
                value += code[curret]
                curret++
            }

            tokens.push({
                type: 'whitespace',
                value,
            })

            continue
        }

        // 运算符
        if (/=|\+|>/.test(char)) {
            let value = ''
            value += char
            curret++

            while (/=|\+|>/.test(code[curret])) {
                value += code[curret]
                curret++
            }

            if (value === '=>') {
                tokens.push({
                    type: 'ArrowFunctionExpression',
                    value
                })
                continue
            }

            tokens.push({
                type: 'operator',
                value
            })

            continue
        }

        // 逗号
        if (/,/.test(char)) {
            tokens.push({
                type: ',',
                value: ','
            })
            curret++
            continue
        }

    }

    return tokens
}

const result = tokenizer('const add = (a, b) => a + b')
// console.log(parser(result));

// 语法分析
const parser = tokens => {
    let current = -1 // 全时指针
    const tem = []

    let token = tokens[current]
    // 解析函数声明
    const parseDeclarations = () => {
        setTem()
        next()

        // 如果字符为‘const’那就是一个声明
        if (token.type === 'identifier' && token.value === 'const') {
            const declarations = {
                type: 'VariableDeclarations',
                kind: token.value
            }

            next()

            if (token.type !== 'identifier') {
                throw new Error('Expected Variable after const')
            }
            declarations.identifierName = token.value
            next()

            if (token.type === 'operator' && token.value === '=') {
                declarations.init = parseFunctionExpression() // 解析=后面的整个函数表达式
            }

            return declarations
        }
    }

    // 解析函数体
    const parseFunctionExpression = () => {
        next()

        let init;
        // 等号后面接的是表达式
        if ((token.type === 'parens' && token.value === '(') || token.type === 'identifier') {
            setTem()
            next()
            while (token.type === 'identifier' || token.type === ',') {
                next()
            }

            if (token.type === 'parens' && token.value === ')') {
                next()

                if (token.type === 'ArrowFunctionExpression') {
                    init = {
                        type: 'ArrowFunctionExpression',
                        params: [],
                        body: {}
                    }

                    backTem()

                    // 解析参数
                    init.params = parseParams()

                    init.body = parseExpression()

                } else {
                    backTem()
                }

            }
        }

        return init
    }


    const parseParams = () => {
        const params = []
        if (token.type === 'parens' && token.value === '(') {
            next()
            while (token.type !== 'parens' && token.value !== ')') {
                if (token.type === 'identifier') {
                    params.push({
                        type: token.type,
                        identifierName: token.value
                    })
                }
                next()
            }
        }
        return params
    }
    const parseExpression = () => {
        next()
        let body;
        while (token.type === 'ArrowFunctionExpression') {
            next()
        }

        if (token.type === 'identifier') {
            body = {
                type: 'BenaryExpression',
                left: {
                    type: 'identifier',
                    identifierName: token.value
                },
                operator: '',
                right: {
                    type: '',
                    identifierName: ''
                }
            }
            next()
            if (token.type === 'operator') {
                body.operator = token.value
            }
            next()
            if (token.type === 'identifier') {
                body.right = {
                    type: 'identifier',
                    identifierName: token.value
                }
            }
        }
        return body
    }
    const setTem = () => {
        tem.push(current)
    }
    const next = () => {
        do {
            ++current
            token = tokens[current] ? tokens[current] : { type: 'eof', value: '' }
        } while (token.type === 'whitespace');
    }
    const backTem = () => {
        current = tem.pop()
        token = tokens[current]
    }

    const ast = {
        type: 'Program',
        body: []
    }

    while (current < tokens.length) {
        const statement = parseDeclarations()
        if (!statement) {
            break
        }
        ast.body.push(statement)
    }

    return ast
}

// AST的转换
const transformer=(ast)=>{
    // 生成新的AST
    const newAST={
        type:'Program',
        body:[]
    }
    ast._context=newAST.body
    traverser(ast,{
        VariableDeclarations:(node,parent)=>{
            let functionDeclaration={//变量声明的节点node
                params:[],//装参数
            }
            if(node.init.type === 'ArrowFunctionExpression'){//箭头函数
                functionDeclaration.type='FunctionDeclaration'
                functionDeclaration.identifierName=node.identifierName
            }
            if(node.init.type === 'BinaryExpression'){//函数体
                functionDeclaration.body={
                    type:'BlockStatement',
                    body:[{//因为函数体里面没有es6的写法，直接返回body
                        type:'ReturnStatement',
                        argument:node.init.body
                    }]
                }
            }
            parent._context.push(functionDeclaration)
        },
        identifier:(node,parent)=>{//节点是一个字符
            // 只是处理箭头函数里面的字符
            if(parent.type==='ArrowFunctionExpression'){//父节点是箭头函数
                ast._context[0].params.push({
                    type:'identifier',
                    identifierName:node.identifierName
                })

            }
        }
    })
    return newAST
}
const AST=parser(result)

// 遍历器：专门遍历AST
const traverser = (ast, visitor) => {

    const traverseArray = (array, parent) => {//节点是数组，递归
        array.forEach(child => {
            tarverseNode(child, parent)
        })
    }

    const tarverseNode = (node, parent) => {//专门用来遍历AST的每个节点
        const method = visitor[node.type]

        if (method) {
            method(node, parent)//处理当前node根节点，和父节点
        }

        switch (node.type) {
            case 'Program'://节点是数组
                traverseArray(node.body, node);
                break;

            case 'VariableDeclarations'://节点是对象
                traverseArray(node.init.params, node.init);
                break;

            case 'identifier'://某个字符，没有子节点
                break;

            default:
                throw new TypeError(node.type)
        }
    }
    tarverseNode(ast, null)//最外层节点的父节点为null
}

// traverser(ast,{
//     VariableDeclarations:()=>{

//     },
//     identifier:()=>{

//     }
// })
const newAST=transformer(AST)
// console.log(newAST);

// 生成器
const generator=(node)=>{
    switch(node.type){
        case 'Program':
            return node.body.map(generator).join('\n')
        case 'FunctionDeclaration':
            return 'function'+" "+node.identifierName+'('+node.params.map(generator)+')'+' '+generator(node.body);
        case 'identifier':
            return node.identifierName;
        case 'BlockStatement':
            return '{'+node.body.map(generator)+'}';
        case 'ReturnStatement':
            return 'return '+generator(node.argument);
        case 'BlockStatement':
            return generator(node.left)+' '+generator(node.right);
        default:
            throw new TypeError(node.type)
    }
}
console.log(generator(newAST));